package work.mediway.mdm.biz.helper;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import work.mediway.mdm.biz.service.patient.RelPatientService;
import work.mediway.mdm.core.constant.MdmConstant;
import work.mediway.mdm.core.util.NumUtil;
import work.mediway.mdm.biz.entity.patient.PaSuspectPatient;
import work.mediway.mdm.biz.entity.patient.RelPatient;
import work.mediway.mdm.biz.vo.patient.PatientDetailVO;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2021/1/18
 */
public class SuspectHelper {

    /**
     * 计算两个患者的相似信息，返回两条完整的数据
     *
     * @param configs            权重配置信息
     * @param majorPatientDetail 主患者详细信息
     * @param minorPatientDetail 次患者详细信息
     * @param result             结果
     */
    public static void computeSuspect(Map<String, String> configs, PatientDetailVO majorPatientDetail, PatientDetailVO minorPatientDetail, List<PaSuspectPatient> result) {
        PaSuspectPatient suspectPatient1 = new PaSuspectPatient();
        PaSuspectPatient suspectPatient2 = new PaSuspectPatient();
        String[] dateTime = StrUtil.splitToArray(DateUtil.now(), StringPool.SPACE);
        // 身份证号相同，表示是同一个人，剩下的不必比较(新生儿的身份证号可能与母亲一致)
        if (StrUtil.isAllNotBlank(majorPatientDetail.getPatPatientCardNo(), minorPatientDetail.getPatPatientCardNo())
                && StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPatientCardNo(), minorPatientDetail.getPatPatientCardNo())) {
            if (StrUtil.isNotBlank(majorPatientDetail.getPatBirthDate())
                    && StrUtil.isNotBlank(minorPatientDetail.getPatBirthDate())
                    && DateUtil.ageOfNow(majorPatientDetail.getPatBirthDate()) != DateUtil.ageOfNow(minorPatientDetail.getPatBirthDate())) {
                return;
            }
            String idWeight = configs.get(MdmConstant.SUSPECT_WIGHT_ID);
            if (!StrUtil.contains(idWeight, StringPool.PERCENT)) {
                idWeight = NumberUtil.formatPercent(Double.parseDouble(Optional.ofNullable(idWeight).orElse("1")), 0);
            }
            // 处理结果，返回
            suspectPatient1.setSuspectRate(idWeight);
            suspectPatient1.setSuspectContent("身份证号相同");
            suspectPatient1.setSuspectPatPatientId(majorPatientDetail.getPatPatientId());
            suspectPatient1.setSuspectRelPatPatientId(minorPatientDetail.getPatPatientId());
            suspectPatient1.setLastUpdateDate(dateTime[0]);
            suspectPatient1.setLastUpdateTime(dateTime[1]);
            List<RelPatient> list = SpringUtil.getBean(RelPatientService.class).list(Wrappers.lambdaQuery(RelPatient.class).eq(RelPatient::getLinkPatientId, majorPatientDetail.getPatPatientId()));
            if (CollUtil.isEmpty(list)) {
                suspectPatient2.setSuspectRate(idWeight);
                suspectPatient2.setSuspectContent("身份证号相同");
                suspectPatient2.setSuspectPatPatientId(minorPatientDetail.getPatPatientId());
                suspectPatient2.setSuspectRelPatPatientId(majorPatientDetail.getPatPatientId());
                suspectPatient2.setLastUpdateDate(dateTime[0]);
                suspectPatient2.setLastUpdateTime(dateTime[1]);
            }
        } else { // 姓名，性别，出生日期，电话号码
            List<String> content = CollUtil.newArrayList();
            double rate = 0.00;

            // 计算姓名相似度
            rate = nameCompute(configs.get(MdmConstant.SUSPECT_WIGHT_NAME), majorPatientDetail, minorPatientDetail, content, rate);

            // 判断电话相似度
            String phoneWeight = configs.get(MdmConstant.SUSPECT_WIGHT_PHONE);
            String phoneTel = configs.get(MdmConstant.SUSPECT_WIGHT_TEL);
            rate = phoneCompute(StrUtil.isAllBlank(phoneWeight, phoneTel) ? null : StrUtil.isNotBlank(phoneWeight) ? phoneWeight : phoneTel
                    , majorPatientDetail, minorPatientDetail, content, rate);

            // 判断姓名，出生日期，电话是否存在相似度，如果存在，再加上性别相似度，如果不存在，结束
            if (!NumberUtil.equals(rate, 0.00)) {
                rate = addSexCompute(configs.get(MdmConstant.SUSPECT_WIGHT_SEX), majorPatientDetail, minorPatientDetail, content, rate);
                //  判断出生日期相似度
                rate = addDobCompute(configs.get(MdmConstant.SUSPECT_WIGHT_DOB), majorPatientDetail, minorPatientDetail, content, rate);
            }
            // 格式化数据，返回计算结果
            if (!StrUtil.equals("0.00", String.valueOf(rate)) && content.size() > 0) {
                suspectPatient1.setSuspectRate(NumberUtil.formatPercent(rate, 0));
                suspectPatient1.setSuspectContent(StrUtil.join(StringPool.COMMA, content));
                suspectPatient1.setSuspectPatPatientId(majorPatientDetail.getPatPatientId());
                suspectPatient1.setSuspectRelPatPatientId(minorPatientDetail.getPatPatientId());
                suspectPatient1.setLastUpdateDate(dateTime[0]);
                suspectPatient1.setLastUpdateTime(dateTime[1]);
                result.add(suspectPatient1);
                // 判断是否已经存在该患者作为主患者合并的信息
                List<RelPatient> list = SpringUtil.getBean(RelPatientService.class)
                        .list(Wrappers.lambdaQuery(RelPatient.class).eq(RelPatient::getLinkPatientId, majorPatientDetail.getPatPatientId()));
                if (CollUtil.isEmpty(list)) {
                    suspectPatient2.setSuspectRate(NumberUtil.formatPercent(rate, 0));
                    suspectPatient2.setSuspectContent(StrUtil.join(StringPool.COMMA, content));
                    suspectPatient2.setSuspectPatPatientId(minorPatientDetail.getPatPatientId());
                    suspectPatient2.setSuspectRelPatPatientId(majorPatientDetail.getPatPatientId());
                    suspectPatient2.setLastUpdateDate(dateTime[0]);
                    suspectPatient2.setLastUpdateTime(dateTime[1]);
                    result.add(suspectPatient2);
                }
            }

        }
    }

    /**
     * 计算姓名相似度
     *
     * @param nameWeight         姓名权重
     * @param majorPatientDetail 主患者信息
     * @param minorPatientDetail 次患者信息
     * @param content            结果内容
     * @param rate               比率
     * @return 相似度
     */
    private static double nameCompute(String nameWeight, PatientDetailVO majorPatientDetail, PatientDetailVO minorPatientDetail, List<String> content, double rate) {
        if (StrUtil.isAllNotBlank(majorPatientDetail.getPatPatientName(), minorPatientDetail.getPatPatientName())
                && StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPatientName(), minorPatientDetail.getPatPatientName())) {
            content.add("姓名相同");
            if (StrUtil.contains(nameWeight, StringPool.PERCENT)) {
                return rate + NumUtil.formatPercent(nameWeight);
            } else {
                return rate + Double.parseDouble(Optional.ofNullable(nameWeight).orElse("0.00"));
            }
        }
        return rate;
    }

    /**
     * 计算电话相似度
     *
     * @param phoneWeight        电话权重
     * @param majorPatientDetail 主患者信息
     * @param minorPatientDetail 次患者信息
     * @param content            结果内容
     * @param rate               比率
     * @return 相似度
     */
    private static double phoneCompute(String phoneWeight, PatientDetailVO majorPatientDetail, PatientDetailVO minorPatientDetail, List<String> content, double rate) {
        if (StrUtil.isAllNotBlank(majorPatientDetail.getPatPhone(), minorPatientDetail.getPatPhone())
                && StrUtil.equalsIgnoreCase(majorPatientDetail.getPatPhone(), minorPatientDetail.getPatPhone())) {
            content.add("电话号码相同");
            if (StrUtil.contains(phoneWeight, StringPool.PERCENT)) {
                return rate + NumUtil.formatPercent(phoneWeight);
            } else {
                return rate + Double.parseDouble(Optional.ofNullable(phoneWeight).orElse("0.00"));
            }
        }
        return rate;
    }

    /**
     * 计算出生日期相似度
     *
     * @param dobWeight          出生日期权重
     * @param majorPatientDetail 主患者信息
     * @param minorPatientDetail 次患者信息
     * @param content            结果内容
     * @param rate               比率
     * @return 相似度
     */
    private static double addDobCompute(String dobWeight, PatientDetailVO majorPatientDetail, PatientDetailVO minorPatientDetail, List<String> content, double rate) {
        if (StrUtil.isAllNotBlank(majorPatientDetail.getPatBirthDate(), minorPatientDetail.getPatBirthDate())
                && StrUtil.equalsIgnoreCase(majorPatientDetail.getPatBirthDate(), minorPatientDetail.getPatBirthDate())) {
            content.add("出生日期相同");
            if (StrUtil.contains(dobWeight, StringPool.PERCENT)) {
                return rate + NumUtil.formatPercent(dobWeight);
            } else {
                return rate + Double.parseDouble(Optional.ofNullable(dobWeight).orElse("0.00"));
            }
        }
        return rate;
    }

    /**
     * 添加其性别相似度计算
     *
     * @param sexWeight          性别相似度比重
     * @param majorPatientDetail 主患者信息
     * @param minorPatientDetail 次患者信息
     * @param content            结果内容
     * @param rate               比率
     * @return 相似度
     */
    private static double addSexCompute(String sexWeight, PatientDetailVO majorPatientDetail, PatientDetailVO minorPatientDetail, List<String> content, double rate) {
        if (StrUtil.isAllNotBlank(majorPatientDetail.getPatSexDesc(), minorPatientDetail.getPatSexDesc())
                && StrUtil.equalsIgnoreCase(majorPatientDetail.getPatSexDesc(), minorPatientDetail.getPatSexDesc())) {
            content.add("性别相同");
            if (StrUtil.contains(sexWeight, StringPool.PERCENT)) {
                return rate + NumUtil.formatPercent(sexWeight);
            } else {
                return rate + Double.parseDouble(Optional.ofNullable(sexWeight).orElse("0.00"));
            }
        }
        return rate;
    }
}